﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;

namespace Sustainalytics.Caching
{
    public class AppMemoryCache : IAppCache
    {
        // memory cache used by this instance
        static MemoryCache _memCache;

        // subscriber action
        Action<AppCacheItemAction> _subscriberAction;


        /// <summary>
        /// Static ctor.
        /// </summary>
        static AppMemoryCache()
        {
            _memCache = CreateMemoryCache();
        }

        public void Add2Set(string key, string value)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Set value.
        /// </summary>
        /// <param name="key"> Key. </param>
        /// <param name="value"> Value. </param>
        public void Set(string key, string value)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new CacheItemKeyNullOrEmptyException();
            }

            if (value == null)
                return;

            _memCache.Set(key, value, null);

            // notify subscriber
            this.NotifySubscribers(new AppCacheItemAction(
                cacheItem: new AppCacheItem(key, value),
                actionType: AppCacheItemActionType.Set));
        }

        public void Set(string key, IEnumerable<string> values)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new CacheItemKeyNullOrEmptyException();
            }

            if (values == null)
                return;

            _memCache.Set(key, values, null);

            // notify subscriber
            this.NotifySubscribers(new AppCacheItemAction(
                cacheItem: new AppCacheItem(key, values),
                actionType: AppCacheItemActionType.Set));
        }

        public string GetString(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new CacheItemKeyNullOrEmptyException();
            }

            string str = _memCache.Get(key) as string;
            return str;
        }

        public IEnumerable<string> GetSet(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new CacheItemKeyNullOrEmptyException();
            }

            IEnumerable<string> values = _memCache.Get(key) as IEnumerable<string>;
            return values;
        }

        public void Remove(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new CacheItemKeyNullOrEmptyException();
            }

            // remove from cache
            object val = _memCache.Remove(key);

            // notify subscriber
            this.NotifySubscribers(new AppCacheItemAction(
                cacheItem: new AppCacheItem(key, val),
                actionType: AppCacheItemActionType.Removed));
        }

        public void Remove(string key, string value)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new CacheItemKeyNullOrEmptyException();
            }

            if (value == null)
                return;

            IEnumerable<string> values = _memCache.Get(key) as IEnumerable<string>;
            if (values!=null)
            {
                var updatedValues = values.ToList();
                updatedValues.Remove(value);

                _memCache.Set(key, updatedValues, null);
            }
            // notify subscriber
            this.NotifySubscribers(new AppCacheItemAction(
                cacheItem: new AppCacheItem(key, value),
                actionType: AppCacheItemActionType.Removed));
        }

        public void Clear()
        {
            _memCache.Dispose();
            _memCache = CreateMemoryCache();
        }

        public void Subscribe(Action<AppCacheItemAction> action)
        {
            if (action == null)
            {
                throw new CacheSubscribeActionNullException();
            }

            _subscriberAction = action;
        }

        private static MemoryCache CreateMemoryCache()
        {
            return new MemoryCache("AppMemoryCache");
        }

        private void NotifySubscribers(AppCacheItemAction cacheItemAction)
        {
            if (this._subscriberAction != null)
            {
                this._subscriberAction(cacheItemAction);
            }
        }


        public void CloseAll()
        {
        }
    }
}
